import ntplib
import time
import threading
import gradio as gr
from datetime import datetime, timezone, timedelta
import tzlocal  # 第三方库，需要安装：pip install tzlocal
import copy
from decimal import Decimal, getcontext

#######################################################
lock_local_time = threading.Lock()
global_local_time = None  # 共享资源
global_time_utc_zone = None  # 共享资源
global_local_time_update = True  # 共享资源

lock_network_time = threading.Lock()
global_network_time = None  # 共享资源
global_network_time_utc_zone = None  # 共享资源
global_network_time_server = None  # 共享资源
global_network_time_update = True

#######################################################
blocks_get_network_time_network_time = None
blocks_get_network_time_network_time_zone = None
blocks_get_network_time_network_time_server = None
blocks_get_local_time_local_time = None
blocks_get_local_time_local_time_zone = None
#######################################################

def get_network_time(ntp_servers, timeout=1):
    """
    尝试从NTP服务器列表中获取网络时间。
    如果服务器超时，则将其移除出列表。
    
    :param ntp_servers: NTP服务器地址列表。
    :param timeout: 连接超时时间（秒）。
    :return: UNIX时间戳和相应的datetime对象，或者None如果所有服务器都失败。
    """
    ntp_client = ntplib.NTPClient()
    for server in ntp_servers[:]:  # 使用列表切片进行遍历，这样可以在循环中修改原始列表
        try:
            response = ntp_client.request(server, version=3, timeout=timeout)
            network_time = datetime.utcfromtimestamp(response.tx_time)
            return network_time, f"UTC+0:00",  server, ntp_servers
        except Exception as e:
            print(f"Could not get time from {server}. Error: {e}")
            ntp_servers.remove(server)  # 移除无法连接的服务器
    return None, None, None, ntp_servers

def get_local_time():
    global_local_time = datetime.now()
    local_timezone = tzlocal.get_localzone()  # 获取本地时区
    global_local_time_zone = datetime.now(local_timezone)
        
    # 通过时区的偏移量判断是东几区或西几区
    offset_hours = global_local_time_zone.utcoffset().total_seconds() / 3600
    global_local_time_zone = f"UTC{'+' if offset_hours >= 0 else ''}{offset_hours}:00"
    return global_local_time, global_local_time_zone

def thread_get_network_time(name):
    print(f"Thread {name}: starting")
    ntp_servers = [
      # 中国境内NTP服务器
      'ntp1.aliyun.com',
      'ntp2.aliyun.com',
      'ntp3.aliyun.com',
      'ntp4.aliyun.com',
      'ntp5.aliyun.com',
      'ntp6.aliyun.com',
      'ntp7.aliyun.com',
      'time1.cloud.tencent.com',
      'time2.cloud.tencent.com',
      'time3.cloud.tencent.com',
      'time4.cloud.tencent.com',
      'time5.cloud.tencent.com',
      's1a.time.edu.cn',
      's1b.time.edu.cn',
      's2c.time.edu.cn',
      's2d.time.edu.cn',
      'ntp.tuna.tsinghua.edu.cn',
      'ntp.bupt.edu.cn',
      'ntp.ntsc.ac.cn',

      # 国际NTP服务器
      'pool.ntp.org',
      '0.pool.ntp.org',
      '1.pool.ntp.org',
      '2.pool.ntp.org',
      '3.pool.ntp.org',
      'time.google.com',
      'time.windows.com',
      'time.nist.gov',
      'tick.usno.navy.mil',
      'tock.usno.navy.mil',
      'time.apple.com',
      'time1.apple.com',
      'time2.apple.com',
      'time3.apple.com',
      'time4.google.com'
    ]

    ntp_servers_enable = copy.deepcopy(ntp_servers)
    # 持续循环获取网络时间
    while True:
        global global_network_time  # Declare as global to modify the global variable
        global global_network_time_utc_zone
        global global_network_time_server
        if not ntp_servers_enable:
            print("All NTP servers are unreachable. Retrying in 30 seconds...")
            time.sleep(10)  # 等待一段时间再重试
            ntp_servers_enable = copy.deepcopy(ntp_servers)
            continue
        with lock_network_time:
            global_network_time, global_network_time_utc_zone, global_network_time_server, ntp_servers_enable = get_network_time(ntp_servers_enable, 5)
        if global_network_time is not None:
#            print(f"Network Server: {server}")
#            print(f"Network time: {global_network_time} UTC")
            pass
        else:
            print("Could not retrieve network time from any servers.")

        # 等待一定时间后再次尝试，避免频繁请求
        time.sleep(1)  # 1hz
    print(f"Thread {name}: finishing")

def thread_get_local_time(name):
    print(f"Thread {name}: starting")
    global global_local_time  # Declare as global to modify the global variable
    global global_local_time_zone
    while True:
        # 获取当前系统时间（精确到微秒）
        with lock_local_time:  # 获取锁
            global_local_time, global_local_time_zone = get_local_time()
        # print(f"Current system time: {global_local_time}, {global_local_time_zone}")
        time.sleep(0.2)  # 5hz
    print(f"Thread {name}: finishing")

def thread_refesh(name, blocks):
    print(f"Thread {name}: starting")
    # while True:
    #     local_time, local_timetamp = Textbox_get_local_time()
    #     network_time, network_timetamp = Textbox_get_network_time()
    #    # 更新界面上的组件
    #     blocks.set_value('text_local_time', local_time)
    #     print(local_time, network_time)
    #     time.sleep(0.04)  # 25hz
    print(f"Thread {name}: finishing")

if __name__ == "__main__":
    # 创建两个线程对象
    thread1 = threading.Thread(target=thread_get_local_time, args=("thread_get_local_time",))
    thread2 = threading.Thread(target=thread_get_network_time, args=("thread_get_network_time",))
    # 启动线程
    thread1.start()
    thread2.start()

#########################################################################################################################
    with gr.Blocks() as block_timestamp:
        def blocks_get_local_time(value = ''):
            global blocks_get_local_time_local_time
            global blocks_get_local_time_local_time_zone
            global global_local_time_update
            if global_local_time_update is True or '更新' == value:
                with lock_local_time:  # 获取锁
                    blocks_get_local_time_local_time = global_local_time
                    blocks_get_local_time_local_time_zone = global_local_time_zone
            # print(f"get Current system time: {global_local_time}, {blocks_get_local_time_local_time}")
            return f"{blocks_get_local_time_local_time}", f"{blocks_get_local_time_local_time_zone}", blocks_get_local_time_local_time.timestamp()

        def blocks_get_network_time(value = ''):
            global blocks_get_network_time_network_time
            global blocks_get_network_time_network_time_zone
            global blocks_get_network_time_network_time_server
            global global_network_time_update
            if global_network_time_update is True or '更新' == value:
                with lock_network_time:  # 获取锁
                    blocks_get_network_time_network_time = global_network_time
                    blocks_get_network_time_network_time_zone = global_network_time_utc_zone
                    blocks_get_network_time_network_time_server = global_network_time_server
            # print(f"get Network time: {global_network_time} {blocks_get_network_time_network_time}")
            if blocks_get_network_time_network_time is None or blocks_get_network_time_network_time_zone is None or blocks_get_network_time_network_time_server is None:
                return "", "", 0, ""
            return f"{blocks_get_network_time_network_time}", f"{blocks_get_network_time_network_time_zone}", blocks_get_network_time_network_time.timestamp(), blocks_get_network_time_network_time_server

        with gr.Row():
            with gr.Column():
                with gr.Row():
                    text_local_time = gr.Textbox(label="系统时间")
                    text_local_time_utc_zone = gr.Textbox(label="UTC时区")
                    text_local_timestamp = gr.Textbox(label="系统时间戳（秒）")
                with gr.Row():
                    with gr.Column(scale=0.5):
                        with gr.Row():
                            button_local_time_start = gr.Button("停止")
                            button_local_time_update = gr.Button(value="更新")
            with gr.Column():
                with gr.Row():
                    text_network_time = gr.Textbox(label="网络时间")
                    text_network_time_utc_zone = gr.Textbox(label="UTC时区")
                    text_network_timestamp = gr.Textbox(label="网络时间戳（秒）")
                with gr.Row():
                    with gr.Column(scale=0.5):
                        with gr.Row():
                            button_network_time_start = gr.Button("停止")
                            button_network_time_update = gr.Button(value="更新")
                    with gr.Column(scale=0.5):
                        label_network_time_server = gr.Label(value="", label="网络时间服务器")
        with gr.Row():
            with gr.Column(scale=0.5):
                with gr.Row():
                    text_timestamp_s = gr.Textbox(label="Unix时间戳（秒）")
                    button_timestamp_s = gr.Button("转换")
            with gr.Column(scale=0.5):
                with gr.Row():
                    text_timestamp_ms = gr.Textbox(label="Unix时间戳（ 毫秒）")
                    button_timestamp_ms = gr.Button("转换")
        with gr.Row():
            with gr.Column(scale=0.5):
                with gr.Row():
                    text_timestamp_us = gr.Textbox(label="Unix时间戳（微妙）")
                    button_timestamp_us = gr.Button("转换")
            with gr.Column(scale=0.5):
                with gr.Row():
                    text_timestamp_ns = gr.Textbox(label="Unix时间戳（纳秒）")
                    button_timestamp_ns = gr.Button("转换")
        with gr.Row():
            with gr.Column(scale=0.5):
                with gr.Row():
                    text_time = gr.Textbox(label="时间（年-月-日 时:分:秒）")
                    button_time = gr.Button("转换")
        with gr.Row():
            timestamp_md = ""
            with open('unix-timestamp.md', 'r') as file:
                timestamp_md = file.read()
            gr.Markdown(timestamp_md)

        def button_local_time_start_click():
            global global_local_time_update
            global_local_time_update = not global_local_time_update
            if global_local_time_update:
                return "停止"
            else:
                return "开始"
        def button_network_time_start_click():
            global global_network_time_update
            global_network_time_update = not global_network_time_update
            if global_network_time_update:
                return "停止"
            else:
                return "开始"

        def blocks_convert_timestamp_s(convert_timestamp_s):
            try:
                timestamp_s = Decimal(convert_timestamp_s)
                str_timestamp_s = str(timestamp_s)
                if '.' in str_timestamp_s:
                    base_time, fraction = str_timestamp_s.split('.')
                else:
                    base_time = str_timestamp_s
                    fraction = '0'
                # 将Unix时间戳转换为datetime对象
                dt_object = datetime.utcfromtimestamp(int(base_time))
                convert_time = dt_object.strftime('%Y-%m-%d %H:%M:%S') + "." + fraction
            except Exception as e:  # 绑定异常到变量e
                # 如果转换失败，输出错误信息
                gr.Warning(f"无效Unix时间戳{convert_timestamp_s}秒: {e}")
                return 0, 0, 0, 0, "1970-01-01 00:00:00.0"
            return timestamp_s, timestamp_s * 1000, timestamp_s * 1000000, timestamp_s * 1000000000, convert_time
        def blocks_convert_timestamp_ms(convert_timestamp_ms):
            try:
                timestamp_s = Decimal(convert_timestamp_ms) / 1000
                str_timestamp_s = str(timestamp_s)
                if '.' in str_timestamp_s:
                    base_time, fraction = str_timestamp_s.split('.')
                else:
                    base_time = str_timestamp_s
                    fraction = '0'
                # 将Unix时间戳转换为datetime对象
                dt_object = datetime.utcfromtimestamp(int(base_time))
                convert_time = dt_object.strftime('%Y-%m-%d %H:%M:%S') + "." + fraction
            except Exception as e:  # 绑定异常到变量e
                # 如果转换失败，输出错误信息
                gr.Warning(f"无效Unix时间戳{convert_timestamp_ms}毫秒: {e}")
                return 0, 0, 0, 0, "1970-01-01 00:00:00.0"
            return timestamp_s, timestamp_s * 1000, timestamp_s * 1000000, timestamp_s * 1000000000, convert_time
        def blocks_convert_timestamp_us(convert_timestamp_us):
            try:
                timestamp_s = Decimal(convert_timestamp_us) / 1000000
                str_timestamp_s = str(timestamp_s)
                if '.' in str_timestamp_s:
                    base_time, fraction = str_timestamp_s.split('.')
                else:
                    base_time = str_timestamp_s
                    fraction = '0'
                # 将Unix时间戳转换为datetime对象
                dt_object = datetime.utcfromtimestamp(int(base_time))
                convert_time = dt_object.strftime('%Y-%m-%d %H:%M:%S') + "." + fraction
            except Exception as e:  # 绑定异常到变量e
                # 如果转换失败，输出错误信息
                gr.Warning(f"无效Unix时间戳{convert_timestamp_us}微秒: {e}")
                return 0, 0, 0, 0, "1970-01-01 00:00:00.0"
            return timestamp_s, timestamp_s * 1000, timestamp_s * 1000000, timestamp_s * 1000000000, convert_time
        def blocks_convert_timestamp_ns(convert_timestamp_ns):
            try:
                timestamp_s = Decimal(convert_timestamp_ns) / 1000000000
                str_timestamp_s = str(timestamp_s)
                if '.' in str_timestamp_s:
                    base_time, fraction = str_timestamp_s.split('.')
                else:
                    base_time = str_timestamp_s
                    fraction = '0'
                # 将Unix时间戳转换为datetime对象
                dt_object = datetime.utcfromtimestamp(int(base_time))
                convert_time = dt_object.strftime('%Y-%m-%d %H:%M:%S') + "." + fraction
            except Exception as e:  # 绑定异常到变量e
                # 如果转换失败，输出错误信息
                gr.Warning(f"无效Unix时间戳{convert_timestamp_ns}纳秒: {e}")
                return 0, 0, 0, 0, "1970-01-01 00:00:00.0"
            return timestamp_s, timestamp_s * 1000, timestamp_s * 1000000, timestamp_s * 1000000000, convert_time
        def blocks_convert_time(convert_time):
            try:
                if '.' in convert_time:
                    base_time, fraction = convert_time.split('.')
                else:
                    base_time = convert_time
                    fraction = '0'
                dt_object = datetime.strptime(base_time, '%Y-%m-%d %H:%M:%S')
                # 将 datetime 对象转换为 UTC 时间戳（整数秒）
                timestamp = dt_object.timestamp()
                # 将小数部分添加到时间戳中
                timestamp_s = Decimal(str(int(timestamp)) + "." + fraction)
            except ValueError as e:
                gr.Warning(f"无效时间 '{convert_time}': {e}")
                return 0, 0, 0, 0, "1970-01-01 00:00:00.0"
            return timestamp_s, timestamp_s * 1000, timestamp_s * 1000000, timestamp_s * 1000000000, convert_time
        
        block_local_time_update1 = block_timestamp.load(blocks_get_local_time, inputs=[], outputs=[text_local_time, text_local_time_utc_zone, text_local_timestamp], every=0.1)
        block_local_time_update2 = block_timestamp.load(blocks_get_network_time, inputs=[], outputs=[text_network_time, text_network_time_utc_zone, text_network_timestamp, label_network_time_server], every=1)
        # button_local_time_start.click(None, inputs=[], outputs=[], cancels=block_local_time_update1)
        # button_network_time_start.click(None, inputs=[], outputs=[], cancels=block_local_time_update2)
        button_local_time_start.click(button_local_time_start_click, inputs=[], outputs=[button_local_time_start])
        button_network_time_start.click(button_network_time_start_click, inputs=[], outputs=[button_network_time_start])
        button_local_time_update.click(blocks_get_local_time, inputs=[button_local_time_update], outputs=[text_local_time, text_local_time_utc_zone, text_local_timestamp])
        button_network_time_update.click(blocks_get_network_time, inputs=[button_network_time_update], outputs=[text_network_time, text_network_time_utc_zone, text_network_timestamp, label_network_time_server])
        button_timestamp_s.click(blocks_convert_timestamp_s, inputs=[text_timestamp_s], outputs=[text_timestamp_s, text_timestamp_ms, text_timestamp_us, text_timestamp_ns, text_time])
        button_timestamp_ms.click(blocks_convert_timestamp_ms, inputs=[text_timestamp_ms], outputs=[text_timestamp_s, text_timestamp_ms, text_timestamp_us, text_timestamp_ns, text_time])
        button_timestamp_us.click(blocks_convert_timestamp_us, inputs=[text_timestamp_us], outputs=[text_timestamp_s, text_timestamp_ms, text_timestamp_us, text_timestamp_ns, text_time])
        button_timestamp_ns.click(blocks_convert_timestamp_ns, inputs=[text_timestamp_ns], outputs=[text_timestamp_s, text_timestamp_ms, text_timestamp_us, text_timestamp_ns, text_time])
        button_time.click(blocks_convert_time, inputs=[text_time], outputs=[text_timestamp_s, text_timestamp_ms, text_timestamp_us, text_timestamp_ns, text_time])
#########################################################################################################################

    thread3 = threading.Thread(target=thread_refesh, args=("thread_refesh", block_timestamp, ))
    thread3.start() 
    block_timestamp.launch()

    # 等待所有线程完成
    thread1.join()
    thread2.join()
    thread3.join()
    print("Done")